﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Runtime.Serialization;
using System;
using System.Threading;
using System.Reflection;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC
{
    public class AttackCommand : Command, ICommandInfo
    {
        public override string HelpText { get { return "Attack another character or creature in the room"; } }
        public override string Example { get { return "attack scary monster"; } }

        public static List<string> Words = new List<string>() { "ATTACK" };

        public override List<string> FirstWords { get { return Words; } }

        public IGameThing FindUsingString(IGameThing source, string input)
        {
            GameThingBaseClass chr = source as GameThingBaseClass;
            
            string[] nextWords = input.Split(" ".ToCharArray(), 2, StringSplitOptions.None);

            if (nextWords.Length < 1)
                return null;

            var targets = chr.FindUsingString<IGameThing>(nextWords[0], 0.55f, FindOptions.SameRoom | FindOptions.WantSingle);
            
            return targets.FirstOrDefault();
        }

        public override CommandToPerform CreateCommand(IGameThing source, string first, string input)
        {
            IGameThing target = FindUsingString(source, input);

            if (target == null)
                return null;

            CommandToPerform cmd = CommandFactory.CreateAttack(source.AssociatedID, target.AssociatedID);
            return cmd;
        }

        public override bool CheckIsValid(IGameThing source, string first, string input)
        {
            return true;
        }

        [MethodVisible]
        public static EventToPerceive CreateAttackObservableEvent(GameChar source, GameChar target)
        {
            return new GeneralEventToPerceive()
            {
                ShowToSource = new Event("You attack ~target.", ViewType.See),
                ShowToObservers = new Event("~source attacks ~target.", ViewType.See),
                ShowToTarget = new Event("~source attacks you!", ViewType.See),
                Sources = new AssociatedIDCollection(source.AssociatedID),
                Targets = new AssociatedIDCollection(target.AssociatedID)
            };
        }

        [MethodVisible]
        public static string CanAttack(CommandToPerform cmd, IGameThing src, IGameThing tar, PropertyData args, PropertyData modifyingArguments)
        {
            GameChar source = src as GameChar;
            GameChar target = tar as GameChar;

            if (source == null || target == null)
                return "Error";

            if (source.LocationInt != target.LocationInt)
                return "That opponent is not here.";

            if (target.IsDead)
                return "The opponent is dead.";

            if (source.IsDead)
                return "You are dead.";

            return string.Empty;
        }

        [MethodVisible]
        public static void AccountForInfluences(string influenceName, GameChar source, GameChar target, PropertyData parameters)
        {
            Globals.InfluenceManager.AccountForInfluences(influenceName, source, target, parameters);
            source.InfluenceCollection.AccountForInfluences(influenceName, source, target, parameters);
            target.InfluenceCollection.AccountForInfluences(influenceName, source, target, parameters);
        }

        [MethodVisible]
        public static List<PerceivedEventAndAudience> Attack(CommandToPerform cmd, IGameThing src, IGameThing tar, PropertyData args, PropertyData modifyingArguments)
        {
            GameChar source = src as GameChar;
            GameChar target = tar as GameChar;
            List<PerceivedEventAndAudience> events = new List<PerceivedEventAndAudience>();

            CombatHandler.Instance.RegisterNewAttack(source, target);

            State stateAttack = source.States.FindStateByName("BasicAttackState");
            State stateBeingAttacked = target.States.FindStateByName("BeingAttackedState");

            if (stateAttack == null)
            {
                stateAttack = StateFactory.CreateBasicAttackState();
                source.States.AddState(stateAttack, 0);
            }

            if (stateBeingAttacked == null)
            {
                stateBeingAttacked = StateFactory.CreateBeingAttackedState();
                target.States.AddState(stateBeingAttacked, 0);
            }

            //// For both attacker and target:
            //// Allow State influence
            //// Allow Ability influence
            //// Allow (equipped?) Object influence
            //IdentifierAndValue movementPointCost = new IdentifierAndValue("MovementPointCost", 2);
            //IdentifierAndValue damagePhysical = new IdentifierAndValue("DamagePhysical", 1);
            //PropertyData parameters = new PropertyData(movementPointCost, damagePhysical);
            //AccountForInfluences("Attack", source, target, parameters);

            //source.EnqueueModification(CommandFactory.AddOrSubtractFromProperty("MovementPoints", 0 - movementPointCost.Value.Int()));
            //target.EnqueueModification(CommandFactory.AddOrSubtractFromProperty("HitPoints", 0 - damagePhysical.Value.Int()));

            //EventToPerceive evt = CreateAttackObservableEvent(source, target);
            //events.Add(new PerceivedEventAndAudience() { Event = evt, Audience = source.GameLocation.Things });
            //target.RegisterAttackFrom(source.AssociatedID);

            return events;
        }
    }

    public static partial class CommandFactory
    {
        [MethodVisible]
        public static CommandToPerform CreateAttack(long source, long target)
        {
            CommandToPerform cmd = new CommandToPerform()
            {
                ApplyToID = source,
                Arguments = new PropertyData(new IdentifierAndValue() { Identifier = "TargetID", Value = target }),
                CheckPermittedMethod = new Method("AttackCommand", "CanAttack"),
                PerformMethod = new Method("AttackCommand", "Attack")
            };
            return cmd;
        }
    }
}
